from fastapi import FastAPI
from sqlalchemy.orm import Session
from starlette.middleware.cors import CORSMiddleware
from starlette.websockets import WebSocket, WebSocketDisconnect

from app import models
from config.config import settings
import routes
from fastapi import Request
from .core.exceptions import register_exception
from .core.web_socket import WebSocketManager, unread_message_count
from .database import engine, SessionLocal
from .models import Conversation
from .services.conversations import ConversationsServices

models.Base.metadata.create_all(bind=engine)
socket_manager = WebSocketManager()


def get_application():
    _app = FastAPI(title=settings.PROJECT_NAME)
    register_exception(_app)
    _app.include_router(routes.router, prefix='/api')
    return _app


app = get_application()

origins = [
    "http://localhost",
    "http://localhost:10172",
]
app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


@app.middleware("http")
async def db_session_middleware(request: Request, call_next):
    # response = Response("Internal server error", status_code=500)
    try:
        request.state.db = SessionLocal()
        response = await call_next(request)
    finally:
        request.state.db.close()
    return response


def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()


@app.websocket("/ws/{user_id}/{page}/{receiver_id}")
async def websocket_endpoint(websocket: WebSocket, user_id: int, page: str, receiver_id: int = None):
    await socket_manager.connect(websocket, user_id)

    if page != 'chat':
        await socket_manager.chat_page_disconnect(user_id)
    if page == 'chat':
        await get_messages(user_id, receiver_id)
        await socket_manager.chat_page_connect(user_id)
    elif page == 'conversation':
        await get_conversion(user_id)
    elif page == 'tabBar':
        unread_count = unread_message_count(user_id)
        unread_data = {"page": "tabBar", 'msg': '获取成功', "data": {"unread_count": unread_count}}
        await socket_manager.connect_message(data=unread_data, receiver_id=user_id)
    try:
        while True:
            data = await websocket.receive_json()
            if page == 'chat':
                await socket_manager.send_message(data, user_id, receiver_id)
            elif page == 'conversation':
                await get_conversion(user_id)
    except WebSocketDisconnect:
        pass
    finally:
        # 关闭连接并将连接从字典中删除
        print('关闭')
        await socket_manager.disconnect(user_id)


# 获取聊天记录
async def get_messages(user_id: int, receiver_id: int):
    messages = ConversationsServices.get_message(user_id, receiver_id)
    messages = [post.obj_to_dict() for post in messages]
    # 已读消息
    await message_read(user_id, receiver_id)
    data = {"page": "chat", 'msg': '获取成功', "data": messages}
    await socket_manager.connect_message(data=data, receiver_id=user_id)


# 已读消息
async def message_read(sender_id: int, receiver_id: int):
    with Session(engine) as session:
        session.query(Conversation).filter_by(creator_id=sender_id, participant_id=receiver_id).update(
            {'unread_messages': 0})
        session.commit()

    unread_count = unread_message_count(sender_id)
    unread_data = {"page": "tabBar", 'msg': '获取成功', "data": {"unread_count": unread_count}}
    await socket_manager.connect_message(data=unread_data, receiver_id=sender_id)
    return True


# 获取聊对话表
async def get_conversion(user_id: int):
    messages = ConversationsServices.get_conversations(user_id)
    conversation_list = [c.obj_to_dict() for c in messages]
    data = {"page": "conversation", 'msg': '获取成功', "data": conversation_list}
    await socket_manager.connect_message(data=data, receiver_id=user_id)
